/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.nio.channels;

import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.spi.SelectorProvider;
import java.util.Set;


/**
 * 可选择通道对象的多路复用器。
 *
 * <p> 选择器可以通过调用该类的open方法来创建，
 * 该方法将使用系统的默认SelectorProvider来创建一个新的选择器。
 * 选择器也可以通过调用自定义SelectorProvider的openSelector方法来创建。
 * 选择器在通过close方法关闭之前一直保持打开状态。
 *
 * <a name="ks"></a>
 *
 * <p> 可选择的频道与选择器的注册由SelectionKey对象表示。
 * 选择器维护三组选择键：
 *
 * <ul>
 *
 *   <li><p> 密钥集包含代表该选择器当前信道注册的密钥。此集合由keys方法返回。</p></li>
 *
 *   <li><p> 所选密钥集是一组密钥，在先前的选择过程中，
 *   检测到每个密钥的通道,都已为key的兴趣集合的一个标记的操作，做好准备。
 *   这个set由selectedKeys返回。
 *   所选密钥集永远是秘钥集合的子集合</p></li>
 *
 *   <li><p> 取消的密钥集是已取消，但其频道尚未注销的密钥集。
 *   这个集合不能直接进入。被取消的密钥集始终是密钥集的子集。</p></li>
 *
 * </ul>
 *
 * <p> 在新创建的选择器中，这三个集合都是空的。
 *
 * <p> 作为通过通道的register方法注册通道的副作用，密钥被添加到选择器的密钥集中。
 * 取消的密钥在选择操作期间从密钥集中移除。密钥集本身不可直接修改。
 *
 * <p> 当键被取消时，键被添加到其选择器的取消键集中，无论是通过关闭其通道还是通过调用其cancel方法。
 * 取消一个键将导致其频道在下一次选择操作中取消注册，此时该键将从选择器的所有密钥集中删除。
 *
 * <a name="sks"></a><p> 
 * 通过选择操作将密钥添加到选定密钥集中。
 * 通过调用集合的remove方法或调用从该集合获取的迭代器的remove方法，可以直接从所选密钥集中移除密钥。
 * 密钥不会以任何其他方式从选定密钥集中移除；
 * 它们不会作为选择操作操作的副作用而移除。
 * 不能将秘钥直接添加到选定的秘钥集合。</p>
 *
 *
 * <a name="selop"></a>
 * <h2>选择</h2>
 *
 * <p> 在每次选择操作期间，可以向选择器的选定键集添加或从中移除，
 * 也可以从其键和取消的键集中移除键。
 * select和selectNow方法现在包括三个步骤：
 * </p>
 *
 * <ol>
 *
 *   <li><p> 取消密钥集中的每个密钥都将从其所属的每个密钥集中移除，并注销其通道。
 *   此步骤将取消的密钥集变空。</p></li>
 *
 *   <li><p> 当选择操作开始时，将查询底层操作系统，
 *   以获取有关每个剩余通道执行由其键的兴趣集标识的任何操作的可读性的更新。
 *   对于至少准备好进行一次操作的通道，将执行以下两个操作之一：</p>
 *
 *   <ol>
 *
 *     <li><p> 如果通道的键不在所选密钥集中，则将其添加到该集合中，
 *     并修改其就绪操作集，以准确识别现在报告通道准备就绪的那些操作。
 *     先前记录在就绪集合中的任何准备就绪信息都将被丢弃。</p></li>
 *
 *     <li><p>否则，通道的键已经在所选的键集中，因此它的就绪操作集将被修改，以标识报告该通道已就绪的任何新操作。
 *     任何先前记录在就绪集合中的准备信息都会被保留；
 *     换句话说，底层系统返回的ready set按位分离到键的当前ready set中。</p></li>
 *
 *   </ol>
 *
 *   如果此步骤开始时密钥集中的所有密钥都有空的兴趣集，
 *   则选定的密钥集或任何密钥的就绪操作集都不会更新。
 *
 *   <li><p> 如果在步骤（2）进行过程中有任何密钥被添加到已取消的密钥集中，则它们将按照步骤（1）进行处理。</p></li>
 *
 * </ol>
 *
 * <p> 一个选择操作是否阻塞以等待一个或多个通道准备就绪，
 * 如果是等待多长时间，这是这三种选择方法之间唯一的本质区别。</p>
 *
 *
 * <h2>并发</h2>
 *
 * <p>选择器本身对于多个并发线程来说是安全的；
 * 但是它们的密钥集则不是。
 *
 * <p> 选择操作按顺序在选择器本身、键集和选定的键集上同步。
 * 在上面的步骤（1）和（3）中，它们还同步于被取消的密钥集。
 *
 * <p> 在进行选择操作时，对选择器键的兴趣集所做的更改对该操作没有影响；
 * 它们将在下一个选择操作中看到。
 *
 * <p> 可随时取消键和关闭频道。
 * 因此，在一个或多个选择器的键集中存在一个键并不意味着该键是有效的或其通道是打开的。
 * 如果有其他线程取消键或关闭通道的任何可能性，应用程序代码应该小心地同步和检查这些条件
 *
 * <p> 在select（）或select（long）方法中被阻塞的线程可能会被其他线程以以下三种方式之一中断：
 *
 * <ul>
 *
 *   <li><p> 通过调用选择器的wakeup方法，
 *   </p></li>
 *
 *   <li><p> 调用选择器的close方法，或
 *   </p></li>
 *
 *   <li><p> 通过调用阻塞线程的中断方法，在这种情况下，
 *   将设置其中断状态，并调用选择器的wakeup方法。</p></li>
 *
 * </ul>
 *
 * <p> close方法以与选择操作相同的顺序同步选择器和所有三个密钥集。
 *
 * <a name="ksc"></a>
 *
 * <p> 选择器的键和所选的键集对于多个并发线程使用通常是不安全的。
 * 如果这样的线程可以直接修改其中一个集合，那么访问应该通过在集合本身上同步来控制。
 * 这些集合的迭代器方法返回的迭代器是快速失败的：
 * 如果在迭代器创建之后对集合进行了修改（除了通过调用iterator自己的remove方法之外），
 * 那么java.util.ConcurrentModificationException会被抛出。</p>
 *
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 *
 * @see SelectableChannel
 * @see SelectionKey
 */

public abstract class Selector implements Closeable {

    /**
     * 初始化一个类
     */
    protected Selector() { }

    /**
     * 打开选择器。
     *
     * <p> 新的选择器是通过调用系统范围默认值SelectorProvider的openSelector方法创建。</p>
     *
     * @return  A new selector
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }

    /**
     * 指示此选择器是否打开。
     *
     * @return <tt>true</tt> if, and only if, this selector is open
     */
    public abstract boolean isOpen();

    /**
     * 返回创建此频道的提供程序。
     *
     * @return  The provider that created this channel
     */
    public abstract SelectorProvider provider();

    /**
     * 返回此选择器的密钥集。
     *
     * <p> 密钥集不可直接修改。
     * 一个密钥只有在它被取消并且它的通道被取消注册之后才会被移除。
     * 任何修改密钥集的尝试都将导致引发UnsupportedOperationException。
     *
     * <p> 秘钥集合ksc不是线程安全的 </p>
     *
     * @return  This selector's key set
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract Set<SelectionKey> keys();

    /**
     * 返回此选择器的选定密钥集。
     *
     * <p> 可以从所选密钥集中删除密钥，但不能直接将其添加到所选密钥集中。
     * 任何向键集中添加对象的尝试都将导致引发UnsupportedOperationException。
     *
     * <p> 所选密钥集不是线程安全的。
     *
     * @return  This selector's selected-key set
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract Set<SelectionKey> selectedKeys();

    /**
     * 选择一组键，其相应通道已准备好进行I/O操作。
     *
     * <p> 此方法执行非阻塞选择操作。
     * 如果自上一次选择操作后没有通道可选择，则此方法立即返回零。
     *
     * <p> 调用此方法将清除以前调用wakeup方法的效果。 </p>
     *
     * @return  The number of keys, possibly zero, whose ready-operation sets
     *          were updated by the selection operation
     *
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract int selectNow() throws IOException;

    /**
     * 
     *
     * <p> 此方法执行阻塞选择操作。
     * 它只在至少选择了一个通道、调用了该选择器的wakeup方法、
     * 中断了当前线程或指定的超时时间过期后（以先到者为准）返回。
     * 
     *
     * <p> 此方法不提供实时保证：它像通过调用Object.wait(long)方法。</p>
     *
     * @param  timeout  If positive, block for up to <tt>timeout</tt>
     *                  milliseconds, more or less, while waiting for a
     *                  channel to become ready; if zero, block indefinitely;
     *                  must not be negative
     *
     * @return  The number of keys, possibly zero,
     *          whose ready-operation sets were updated
     *
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     *
     * @throws  IllegalArgumentException
     *          If the value of the timeout argument is negative
     */
    public abstract int select(long timeout)
        throws IOException;

    /**
     * 选择一组键，其相应通道已准备好进行I/O操作。
     *
     * <p> 此方法执行阻塞选择操作。
     * 它只在至少选择一个通道、调用该选择器的wakeup方法或中断currentthread后返回。</p>
     *
     * @return  The number of keys, possibly zero,
     *          whose ready-operation sets were updated
     *
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract int select() throws IOException;

    /**
     * 使尚未返回的第一个选择操作立即返回。
     *
     * <p>如果另一个线程当前在调用select（）或select（long）方法时被阻塞，则该调用将立即返回。
     * 如果当前没有正在进行的选择操作，则这些方法之一的下一次调用将立即返回，除非在同时调用selectNow（）方法。
     * 在任何情况下，该调用返回的值可能不是零。
     * 随后对select（）或select（long）方法的调用将一如既往地阻塞，除非同时再次调用此方法。
     *
     * <p> 在两个连续的选择操作之间多次调用此方法与只调用一次具有相同的效果。</p>
     *
     * @return  This selector
     */
    public abstract Selector wakeup();

    /**
     * 关闭此选择器。
     *
     * <p> 如果某个线程当前被阻塞在此选择器的选择方法中，
     * 那么它将被中断，就像调用选择器的wakeup方法一样。
     *
     * <p> 仍与此选择器关联的任何未取消键都将失效，它们的通道将被取消注册，
     * 并且与此选择器关联的任何其他资源都将被释放。
     *
     * <p>如果此选择器已关闭，则调用此方法无效。
     *
     * <p> 关闭选择器后，任何进一步尝试使用它（调用此方法或wakeup方法除外）
     * 都将引发ClosedSelectorException。</p>
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    public abstract void close() throws IOException;

}
